/***************************************************************************
 *   Copyright (C) 2012                                                    *
 *   Anatole Duprat <anatole.duprat@gmail.com>                             *
 *   Charles Bulckaen  <xtrium@frequency.fr>                               *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU General Public License           *
 *   as published by the Free Software Foundation; either version 2        *
 *   of the License, or (at your option) any later version.                *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
 ***************************************************************************/



#include "shadereditorwidget.hh"
#include "ui_shadereditorwidget.h"

ShaderEditorWidget::ShaderEditorWidget(QWidget *parent) :
    QDockWidget(parent),
    ui(new Ui::ShaderEditorWidget)
{
    ui->setupUi(this);
    _autoUpdate = false;

    _compileTimer = new QTimer();
    _compileTimer->setSingleShot(true);
    _compileTimer->setInterval(1000);
    connect(_compileTimer, SIGNAL(timeout()), this, SLOT(fireupCompilation()));

    _compilePostTimer = new QTimer();
    _compilePostTimer->setSingleShot(true);
    _compilePostTimer->setInterval(1000);
    connect(_compilePostTimer, SIGNAL(timeout()), this, SLOT(fireupPostCompilation()));
}


QString ShaderEditorWidget::getVertexText(void){
    return ui->vertEdit->toPlainText();
}
QString ShaderEditorWidget::getFragmentText(void){
    return ui->fragEdit->toPlainText();
}
QString ShaderEditorWidget::getVertexPostText(void){
    return ui->vertPostEdit->toPlainText();
}
QString ShaderEditorWidget::getFragmentPostText(void){
    return ui->fragPostEdit->toPlainText();
}


ShaderEditorWidget::~ShaderEditorWidget()
{
    delete ui;
}

void ShaderEditorWidget::setVertexText(QString str)
{
    ui->vertEdit->setHtml(colorSyntax(str));
}

void ShaderEditorWidget::setFragmentText(QString str)
{
    ui->fragEdit->setHtml(colorSyntax(str));
}



void ShaderEditorWidget::setVertexPostText(QString str)
{
    ui->vertPostEdit->setHtml(colorSyntax(str));
}

void ShaderEditorWidget::setFragmentPostText(QString str)
{
    ui->fragPostEdit->setHtml(colorSyntax(str));
}


void ShaderEditorWidget::setAutoUpdate(bool mu)
{
    _autoUpdate = mu;
}

void ShaderEditorWidget::prepareCompilationFireup()
{
    //ui->vertEdit->setHtml(colorSyntax(ui->vertEdit->toPlainText()));
    //ui->fragEdit->setHtml(colorSyntax(ui->fragEdit->toPlainText()));
    if(_autoUpdate)
    {
        _compileTimer->start();
    }
}
void ShaderEditorWidget::preparePostCompilationFireup()
{
    //ui->vertPostEdit->setHtml(colorSyntax(ui->vertPostEdit->toPlainText()));
    //ui->fragPostEdit->setHtml(colorSyntax(ui->fragPostEdit->toPlainText()));
    if(_autoUpdate)
    {
        _compilePostTimer->start();
    }
}
void ShaderEditorWidget::setSceneStatus(QString str)
{
    ui->sceneLabel->setText("Scene status : " + str);
}
void ShaderEditorWidget::setPostStatus(QString str)
{
    ui->postLabel->setText("Post process status : " + str);
}

void ShaderEditorWidget::fireupCompilation()
{
    bool tmp = _autoUpdate;

    int vtcp = ui->vertEdit->textCursor().position();
    int ftcp = ui->fragEdit->textCursor().position();
    _autoUpdate = false;
    ui->vertEdit->setHtml(colorSyntax(ui->vertEdit->toPlainText()));
    ui->fragEdit->setHtml(colorSyntax(ui->fragEdit->toPlainText()));
    QTextCursor vtc = ui->vertEdit->textCursor(); vtc.setPosition(vtcp);
    QTextCursor ftc = ui->fragEdit->textCursor(); ftc.setPosition(ftcp);
    ui->vertEdit->setTextCursor(vtc);
    ui->fragEdit->setTextCursor(ftc);

    _autoUpdate = tmp;
    emit shaderChanged(ui->vertEdit->toPlainText(), ui->fragEdit->toPlainText());
}


void ShaderEditorWidget::fireupPostCompilation()
{
    bool tmp = _autoUpdate;

    int vtcp = ui->vertPostEdit->textCursor().position();
    int ftcp = ui->fragPostEdit->textCursor().position();
    _autoUpdate = false;
    ui->vertPostEdit->setHtml(colorSyntax(ui->vertPostEdit->toPlainText()));
    ui->fragPostEdit->setHtml(colorSyntax(ui->fragPostEdit->toPlainText()));
    QTextCursor vtc = ui->vertPostEdit->textCursor(); vtc.setPosition(vtcp);
    QTextCursor ftc = ui->fragPostEdit->textCursor(); ftc.setPosition(ftcp);
    ui->vertPostEdit->setTextCursor(vtc);
    ui->fragPostEdit->setTextCursor(ftc);

    _autoUpdate = tmp;
    emit shaderPostChanged(ui->vertPostEdit->toPlainText(), ui->fragPostEdit->toPlainText());
}

QString ShaderEditorWidget::colorSyntax(QString in)
{
    QString sourceText = QString(in);

    /** HTML transformations **/
    sourceText.replace("<", "&lt;");
    sourceText.replace(">", "&gt;");
    //sourceText.replace("\\t","    ");
    sourceText.replace("    ", "&nbsp;&nbsp;&nbsp;&nbsp;");
    sourceText.replace("  ", "&nbsp;&nbsp;");
    sourceText.replace("\r\n", "\n");
    sourceText.replace("\r", "\n");

    /** Syntax coloring transformations **/
    // comments
    QRegExp scre = QRegExp("\\/\\/(.*)\\n"); scre.setMinimal(true); sourceText.replace(scre, "<span style=\"color: #888a85;\">//\\1\n</span>");
    QRegExp lcre = QRegExp("\\/\\*(.*)\\*\\/"); lcre.setMinimal(true); sourceText.replace(lcre, "<span style=\"color: #888a85;\">/*\\1*/</span>");

    // keywords
    sourceText.replace(QRegExp("\\b(uniform|attribute|varying|struct)\\b"), "<span style=\"font-weight: bold; color: #8ade35;\">\\1</span>");
    sourceText.replace(QRegExp("\\b(if|else|for|do|while|return|switch|case|const|false|true)\\b"), "<span style=\"font-weight: bold; color: #FFFFFF;\">\\1</span>");
    sourceText.replace(QRegExp("\\b(mix|clamp|normalize|smoothstep|dot|reflect|refract|distance|length|min|max|exp|pow|abs|texture1D|texture2D|texture3D)\\b"), "<span style=\"font-weight: bold; color: #e8e8e8;\">\\1</span>");
    sourceText.replace(QRegExp("\\b(void|bool|bvec2|vec3|bvec4|int|ivec2|ivec3|ivec4|float|vec2|vec3|vec4|mat2|mat3|mat4|sampler2D|sampler3D|in|out)\\b"), "<span style=\"font-weight: bold; color: #8ade35;\">\\1</span>");
    sourceText.replace(QRegExp("\\b(gl_TexCoord|gl_MultiTexCoord0|gl_MultiTexCoord1|gl_MultiTexCoord2|gl_MultiTexCoord3|gl_Vertex|gl_Position|gl_Normal)\\b"), "<span style=\"font-weight: bold; color: #FFFFFF;\">\\1</span>");
    sourceText.replace(QRegExp("\\b(gl_FragData|gl_FragColor|gl_FragCoord|gl_LightSources)\\b"), "<span style=\"font-weight: bold; color: #e8e8e8;\">\\1</span>");

    // numbers
    sourceText.replace(QRegExp("(-?\\d+\\.\\d+)e-?\\d"), "<span style=\" color: #ce5c00;\">\\1</span>");
    sourceText.replace(QRegExp("(-?\\d+\\.)e-?\\d"), "<span style=\" color: #ce5c00;\">\\1</span>");
    sourceText.replace(QRegExp("(-?\\.\\d+)e-?\\d"), "<span style=\" color: #ce5c00;\">\\1</span>");
    sourceText.replace(QRegExp("(-?\\d+\\.\\d+)"), "<span style=\" color: #ce5c00;\">\\1</span>");
    sourceText.replace(QRegExp("(-?\\d+\\.)"), "<span style=\" color: #ce5c00;\">\\1</span>");
    sourceText.replace(QRegExp("(-?\\.\\d+)"), "<span style=\" color: #ce5c00;\">\\1</span>");

    // preprocessor directivessalut
    QRegExp dere = QRegExp("\n() *)#( *)(ifdef|ifndef|define|else|endif|pragma|version) (.*)\n"); dere.setMinimal(true); sourceText.replace(dere, "\n<span style=\"color: #907d99;\">\n\\1#\\2\\3 \\4\n</span>");

    sourceText.replace("\n", "<br />");
    return sourceText.append("</div>").prepend("<div style=\"font-family: consolas, lucida console, system;\">");
}
